home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvibook / libtex / dvi_draw.c < prev    next >
C/C++ Source or Header  |  1994-03-18  |  10KB  |  391 lines

  1. /*
  2.  * Support drawing routines for TeXsun and TeX
  3.  *
  4.  * Copyright, (C) 1987, 1988 Tim Morgan, UC Irvine
  5.  * Copyright 1989 Dirk Grunwald (extensions & fixes)
  6.  * 
  7.  * Permission to use, copy, modify, distribute, and sell this software
  8.  * and its documentation for any purpose is hereby granted without fee,
  9.  * provided that the above copyright notice appear in all copies and that
  10.  * both that copyright notice and this permission notice appear in
  11.  * supporting documentation, and that the name of Tim Morgan, Dirk
  12.  * Grunwald or M.I.T. not be used in advertising or publicity
  13.  * pertaining to distribution of the software without specific,
  14.  * written prior permission.  Tim Morgan, Dirk Grunwald and M.I.T.
  15.  * makes no representations about the suitability of
  16.  * this software for any purpose.  It is provided "as is" without express
  17.  * or implied warranty.
  18.  * 
  19.  * TIM MORGAN,
  20.  * DIRK GRUNWALD AND M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  21.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22.  * FITNESS, IN NO EVENT SHALL M.I.T.  BE LIABLE FOR ANY SPECIAL, INDIRECT
  23.  * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  24.  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  25.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  26.  * OR PERFORMANCE OF THIS SOFTWARE.
  27.  * 
  28.  * Author:
  29.  *     Tim Morgan
  30.  *    Dept. of Computer Science
  31.  *    Univ. of Calf. at Irvine
  32.  *
  33.  *     Dirk Grunwald
  34.  *     Dept. of Computer Science
  35.  *     
  36.  *
  37.  * At the time these routines are called, the values of hh and vv should
  38.  * have been updated to the upper left corner of the graph (the position
  39.  * the \special appears at in the dvi file).  Then the coordinates in the
  40.  * graphics commands are in terms of a virtual page with axes oriented the
  41.  * same as the Imagen and the SUN normally have:
  42.  *
  43.  *                      0,0
  44.  *                       +-----------> +x
  45.  *                       |
  46.  *                       |
  47.  *                       |
  48.  *                      \ /
  49.  *                       +y
  50.  *
  51.  * Angles are measured in the conventional way, from +x towards +y.
  52.  * Unfortunately, that reverses the meaning of "counterclockwise"
  53.  * from what it's normally thought of.
  54.  *
  55.  * A lot of floating point arithmetic has been converted to integer
  56.  * arithmetic for speed.  In some places, this is kind-of kludgy, but
  57.  * it's worth it.
  58.  */
  59.  
  60. static char *rcsid="$Header: /usr/local/src/Uiuctex/libtex/RCS/dvi_draw.c,v 1.3 88/02/19 17:00:34 grunwald Exp Locker: grunwald $" ;
  61.  
  62. #include    <math.h>
  63. #include    <stdio.h>
  64. #include    <ctype.h>
  65.  
  66. #define    MAXPOINTS    300    /* Max points in a path */
  67. #define    TWOPI        (3.14159265359*2.0)
  68. #define    MAX_PEN_SIZE    7    /* Max pixels of pen width */
  69.  
  70.  
  71. static int xx[MAXPOINTS], yy[MAXPOINTS];    /* Path in milli-inches */
  72. static int path_len = 0;    /* # points in current path */
  73. int pen_size = 1;        /* Pixel width of lines drawn */
  74. #define    FALSE    0
  75. #define    TRUE    1
  76. int whiten = FALSE, shade = FALSE, blacken = FALSE;
  77.  
  78. extern void dot_at(), line_btw(), do_attribute_path();
  79.  
  80. #define    shrink_factor    shrinkFactor[currentShrink]
  81.  
  82. /* Unfortunately, these values also appear in dvisun.c */
  83. #define    xRESOLUTION    (dviDPI/shrink_factor)
  84. #define    yRESOLUTION    (dviDPI/shrink_factor)
  85.  
  86. extern int dviDPI, currentShrink, shrinkFactor[];
  87.  
  88.  
  89. /*
  90.  * Issue warning/error messages
  91.  */
  92. void Fatal(msg)
  93. char *msg;
  94. {
  95.     fprintf(stderr, "%s\n", msg);
  96.     exit(1);
  97. }
  98.  
  99. static void Warning(fmt, msg)
  100. char *fmt, *msg;
  101. {
  102.     fprintf(stderr, fmt, msg);
  103.     fputc ('\n', stderr);
  104. }
  105.  
  106.  
  107. /*
  108.  * Set the size of the virtual pen used to draw in milli-inches
  109.  */
  110. /* ARGSUSED */
  111. void set_pen_size(cp)
  112. char *cp;
  113. {
  114.     int ps;
  115.  
  116.     if (sscanf(cp, " %d ", &ps) != 1) {
  117.     Warning("illegal .ps command format: %s", cp);
  118.     return;
  119.     }
  120.     pen_size = (ps*(xRESOLUTION+yRESOLUTION) + 1000) / 2000;
  121.     if (pen_size < 1) pen_size = 1;
  122.     else if (pen_size > MAX_PEN_SIZE) pen_size = MAX_PEN_SIZE;
  123. }
  124.  
  125.  
  126. /*
  127.  * Print the line defined by previous path commands
  128.  */
  129. void flush_path()
  130. {
  131.     register int i;
  132.     int last_min_x, last_max_x, last_min_y, last_max_y;
  133.  
  134.     last_min_x = 30000;    last_min_y = 30000;
  135.     last_max_x = -30000; last_max_y = -30000;
  136.     for (i=1; i<path_len; i++) {
  137.     if (xx[i] > last_max_x) last_max_x = xx[i];
  138.     if (xx[i] < last_min_x) last_min_x = xx[i];
  139.     if (yy[i] > last_max_y) last_max_y = yy[i];
  140.     if (yy[i] < last_min_y) last_min_y = yy[i];
  141.     line_btw(xx[i], yy[i], xx[i+1], yy[i+1]);
  142.     }
  143.     if (xx[path_len] > last_max_x) last_max_x = xx[path_len];
  144.     if (xx[path_len] < last_min_x) last_min_x = xx[path_len];
  145.     if (yy[path_len] > last_max_y) last_max_y = yy[path_len];
  146.     if (yy[path_len] < last_min_y) last_min_y = yy[path_len];
  147.     path_len = 0;
  148.     do_attribute_path(last_min_x, last_max_x, last_min_y, last_max_y);
  149. }
  150.  
  151.  
  152. /*
  153.  * Print a dashed line along the previously defined path, with
  154.  * the dashes/inch defined.
  155.  */
  156. void flush_dashed(cp, dotted)
  157. char *cp;
  158. int dotted;
  159. {
  160.     int i, numdots, x0, y0, x1, y1;
  161.     int cx0, cy0, cx1, cy1;
  162.     float inchesperdash;
  163.     double d, spacesize, a, b, dx, dy, milliperdash;
  164.  
  165.     if (sscanf(cp, " %f ", &inchesperdash) != 1) {
  166.     Warning("illegal format for dotted/dashed line: %s", cp);
  167.     return;
  168.     }
  169.     if (path_len <= 1 || inchesperdash <= 0.0) {
  170.     Warning("illegal conditions for dotted/dashed line");
  171.     return;
  172.     }
  173.     milliperdash = inchesperdash * 1000.0;
  174.     x0 = xx[1];    y0 = yy[1];
  175.     x1 = xx[2];    y1 = yy[2];
  176.     dx = x1 - x0;
  177.     dy = y1 - y0;
  178.     if (dotted) {
  179.     numdots = sqrt(dx*dx + dy*dy) / milliperdash + 0.5;
  180.     if ( numdots == 0 ) {    /* always draw at least one dot */
  181.       numdots = 1;
  182.     }
  183.     for (i=0; i <= numdots; i++) {
  184.         a = (float) i / (float) numdots;
  185.         cx0 = x0 + a*dx + 0.5;
  186.         cy0 = y0 + a*dy + 0.5;
  187.         dot_at(cx0, cy0);
  188.     }
  189.     }
  190.     else {
  191.     d = sqrt(dx*dx + dy*dy);
  192.     if (d <= 2.0*milliperdash)
  193.         line_btw(x0, y0, x1, y1);
  194.     else {
  195.         numdots = d / (2.0*milliperdash) + 1.0;
  196.         spacesize = (d - numdots * milliperdash) / (numdots - 1);
  197.         for (i=0; i<numdots-1; i++) {
  198.         a = i * (milliperdash + spacesize) / d;
  199.         b = a + milliperdash / d;
  200.         cx0 = x0 + a*dx + 0.5;
  201.         cy0 = y0 + a*dy + 0.5;
  202.         cx1 = x0 + b*dx + 0.5;
  203.         cy1 = y0 + b*dy + 0.5;
  204.         line_btw(cx0, cy0, cx1, cy1);
  205.         b += spacesize / d;
  206.         }
  207.         cx0 = x0 + b*dx + 0.5;
  208.         cy0 = y0 + b*dy + 0.5;
  209.         line_btw(cx0, cy0, x1, y1);
  210.     }
  211.     }
  212.     path_len = 0;
  213. }
  214.  
  215.  
  216. /*
  217.  * Add a point to the current path
  218.  */
  219. void add_path(cp)
  220. char *cp;
  221. {
  222.     int pathx, pathy;
  223.  
  224.     if (++path_len >= MAXPOINTS) Fatal("Too many points");
  225.     if (sscanf(cp, " %d %d ", &pathx, &pathy) != 2)
  226.     Fatal("Malformed path command");
  227.     xx[path_len] = pathx;
  228.     yy[path_len] = pathy;
  229. }
  230.  
  231.  
  232. /*
  233.  * Draw to a floating point position
  234.  */
  235. static void im_fdraw(x, y)
  236. double x,y;
  237. {
  238.     if (++path_len >= MAXPOINTS) Fatal("Too many arc points");
  239.     xx[path_len] = x + 0.5;
  240.     yy[path_len] = y + 0.5;
  241. }
  242.  
  243.  
  244. /*
  245.  * Draw an arc
  246.  */
  247. void arc(cp)
  248. char *cp;
  249. {
  250.     int xc, yc, xrad, yrad, n;
  251.     float start_angle, end_angle, angle, theta, r;
  252.     double xradius, yradius, xcenter, ycenter;
  253.  
  254.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
  255.     &end_angle) != 6) {
  256.     Warning("illegal arc specification: %s", cp);
  257.     return;
  258.     }
  259.     /* We have a specialized fast way to draw closed circles/ellipses */
  260.     if (start_angle <= 0.0 && end_angle >= 6.282) {
  261.     draw_ellipse(xc, yc, xrad, yrad);
  262.     return;
  263.     }
  264.     xcenter = xc;
  265.     ycenter = yc;
  266.     xradius = xrad;
  267.     yradius = yrad;
  268.     r = (xradius + yradius) / 2.0;
  269.     theta = sqrt(1.0 / r);
  270.     n = 0.3 * TWOPI / theta + 0.5;
  271.     if (n < 12) n = 12;
  272.     else if (n > 80) n = 80;
  273.     n /= 2;
  274.     theta = TWOPI / n;
  275.     flush_path();
  276.     im_fdraw( xcenter + xradius*cos(start_angle),
  277.         ycenter + yradius*sin(start_angle) );
  278.     angle = start_angle + theta;
  279.     while (angle < end_angle) {
  280.     im_fdraw(xcenter + xradius*cos(angle),
  281.          ycenter + yradius*sin(angle) );
  282.     angle += theta;
  283.     }
  284.     im_fdraw(xcenter + xradius*cos(end_angle),
  285.         ycenter + yradius*sin(end_angle) );
  286.     flush_path();
  287. }
  288.  
  289.  
  290. /*
  291.  * APPROXIMATE integer distance between two points
  292.  */
  293. #define    dist(x0, y0, x1, y1)    (abs(x0-x1)+abs(y0-y1))
  294.  
  295.  
  296. /*
  297.  * Draw a spline along the previously defined path
  298.  */
  299. void flush_spline()
  300. {
  301.     int xp, yp, N, lastx=(-1), lasty;
  302.     int t1, t2, t3, steps, j;
  303.     register int i, w;
  304.  
  305. #ifdef    lint
  306.     lasty = -1;
  307. #endif
  308.     N = path_len + 1;
  309.     xx[0] = xx[1];    yy[0] = yy[1];
  310.     xx[N] = xx[N-1];    yy[N] = yy[N-1];
  311.     for (i=0; i<N-1; i++) {    /* interval */
  312.     steps = (dist(xx[i], yy[i], xx[i+1], yy[i+1]) +
  313.          dist(xx[i+1], yy[i+1], xx[i+2], yy[i+2])) / 80;
  314.     for (j=0; j<steps; j++) {    /* points within */
  315.         w = (j*1000 + 500) / steps;
  316.         t1 = w * w / 20;
  317.         w -= 500;
  318.         t2 = (750000 - w * w) / 10;
  319.         w -= 500;
  320.         t3 = w * w / 20;
  321.         xp = (t1*xx[i+2] + t2*xx[i+1] + t3*xx[i] + 50000) / 100000;
  322.         yp = (t1*yy[i+2] + t2*yy[i+1] + t3*yy[i] + 50000) / 100000;
  323.         if (lastx > -1) line_btw(lastx, lasty, xp, yp);
  324.         lastx = xp;
  325.         lasty = yp;
  326.     }
  327.     }
  328.     path_len = 0;
  329. }
  330.  
  331.  
  332. /*
  333.  * Shade the last box, circle, or ellipse
  334.  */
  335. void shade_last()
  336. {
  337.     blacken = whiten = FALSE;
  338.     shade = TRUE;
  339. }
  340.  
  341.  
  342. /*
  343.  * Make the last box, circle, or ellipse, white inside (shade with white)
  344.  */
  345. void whiten_last()
  346. {
  347.     whiten = TRUE;
  348.     blacken = shade = FALSE;
  349. }
  350.  
  351.  
  352. /*
  353.  * Make last box, etc, black inside
  354.  */
  355. void blacken_last()
  356. {
  357.     blacken = TRUE;
  358.     whiten = shade = FALSE;
  359. }
  360.  
  361.  
  362. /*
  363.  * Draw an ellipse with the indicated center and radices.
  364.  */
  365. draw_ellipse(xc, yc, xr, yr)
  366. int xc, yc, xr, yr;
  367. {
  368.     double angle, theta;
  369.     int n, px0, py0, px1, py1;
  370.  
  371.     angle = (xr + yr) / 2.0;
  372.     theta = sqrt(1.0 / angle);
  373.     n = TWOPI / theta + 0.5;
  374.     if (n < 12) n = 12;
  375.     else if (n > 80) n = 80;
  376.     n /= 2;
  377.     theta = TWOPI / n;
  378.  
  379.     angle = 0.0;
  380.     px0 = xc + xr;    /* cos(0) = 1 */
  381.     py0 = yc;        /* Sin(0) = 0 */
  382.     while ((angle += theta) <= TWOPI) {
  383.     px1 = xc + xr*cos(angle) + 0.5;
  384.     py1 = yc + yr*sin(angle) + 0.5;
  385.     line_btw(px0, py0, px1, py1);
  386.     px0 = px1;
  387.     py0 = py1;
  388.     }
  389.     line_btw(px0, py0, xc + xr, yc);
  390. }
  391.